package com.example.mywebrtc.util;

import static com.example.mywebrtc.util.Constant.PLAY;
import static com.example.mywebrtc.util.Constant.SERVER_IP;

import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import com.example.mywebrtc.ProxyVideoSink;
import com.example.mywebrtc.bean.LocalSdpBean;
import com.example.mywebrtc.bean.SdpBean;
import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.DataChannel;
import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.Logging;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.MediaStreamTrack;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RtpReceiver;
import org.webrtc.RtpTransceiver;
import org.webrtc.SdpObserver;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoTrack;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Objects;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class WebRTCUtil implements PeerConnection.Observer, SdpObserver {
    private static final String TAG = WebRTCUtil.class.getSimpleName();
    private EglBase eglBase;
    private PeerConnection peerConnection;
    private PeerConnectionFactory peerConnectionFactory;
    private Context context;
    private SurfaceViewRenderer surfaceViewRenderer;
    private static final String API = "http://192.168.117.157:1985/rtc/v1/play/";
    private static final String STREAM_URL = "webrtc://192.168.117.157/live/livestream";

    public WebRTCUtil(Context context, SurfaceViewRenderer surfaceViewRenderer, EglBase eglBase) {
        this.context = context;
        this.surfaceViewRenderer = surfaceViewRenderer;
        this.eglBase = eglBase;
        init();
    }

    private void init() {
        peerConnectionFactory = getPeerConnectionFactory(context);
        Logging.enableLogToDebugOutput(Logging.Severity.LS_NONE);
        peerConnection = peerConnectionFactory.createPeerConnection(getConfig(), this);
        peerConnection.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO,
                new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY));
        peerConnection.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO,
                new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY));
        peerConnection.createOffer(this, new MediaConstraints());
    }

    private PeerConnectionFactory getPeerConnectionFactory(Context context) {
        PeerConnectionFactory.InitializationOptions initializationOptions = PeerConnectionFactory.InitializationOptions.builder(context)
                .setEnableInternalTracer(true)
                .setFieldTrials("WebRTC-H264HighProfile/Enabled/")
                .createInitializationOptions();

        // 构造Factory
        PeerConnectionFactory.initialize(initializationOptions);

        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();

        return PeerConnectionFactory.builder()
                .setVideoDecoderFactory(new DefaultVideoDecoderFactory(eglBase.getEglBaseContext()))
                .setVideoEncoderFactory(new DefaultVideoEncoderFactory(eglBase.getEglBaseContext(), false, true))
                .setOptions(options)
                .createPeerConnectionFactory();
    }

    private PeerConnection.RTCConfiguration getConfig() {
        PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(new ArrayList<>());
        //关闭分辨率变换
        rtcConfig.enableCpuOveruseDetection = false;
        //修改模式 PlanB无法使用仅接收音视频的配置
        rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;
        return rtcConfig;
    }

    private void startWebRTC(String sdp) {
        OkHttpClient client = new OkHttpClient();
        MediaType jsonType = MediaType.parse("json:application/json;charset=utf-8");
        RequestBody requestBody = RequestBody.create(jsonType, SdpUtils.getSimpleSdp(sdp));
        Request request = new Request.Builder().addHeader("x-camera-id", "0")
                .url(SERVER_IP + PLAY).post(requestBody).build();
        client.newCall(request).enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {
                Log.d("okhttp:onfailure", e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                Log.d(TAG, "onResponse -> " + result);
                result = result.replaceAll("\n", "");
                if (!TextUtils.isEmpty(result)) {
                    SdpBean sdpBean = new Gson().fromJson(result, SdpBean.class);
                    if (sdpBean.getCode() == 400) {
                        LocalSdpBean localSdpBean = new Gson().fromJson(sdpBean.getSdp(), LocalSdpBean.class);
                        startWebRTC(SdpUtils.getStdSDP(localSdpBean));
                        return;
                    }
                    if (!TextUtils.isEmpty(sdpBean.getSdp())) {
                        if (peerConnection != null) {
                            SessionDescription remoteSpd = new SessionDescription(SessionDescription.Type.ANSWER, sdpBean.getSdp());
                            peerConnection.setRemoteDescription(WebRTCUtil.this, remoteSpd);
                        }
                    }
                }
            }
        });
    }

    @Override
    public void onSignalingChange(PeerConnection.SignalingState signalingState) {
        Log.d(TAG, "onSignalingChange: ");
    }

    @Override
    public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
        Log.d(TAG, "onIceConnectionChange: ");
    }

    @Override
    public void onIceConnectionReceivingChange(boolean b) {
        Log.d(TAG, "onIceConnectionReceivingChange: ");
    }

    @Override
    public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {
        Log.d(TAG, "onIceGatheringChange: ");
    }

    @Override
    public void onIceCandidate(IceCandidate iceCandidate) {
        peerConnection.addIceCandidate(iceCandidate);
        Log.d(TAG, "onIceCandidate: ");
    }

    @Override
    public void onIceCandidatesRemoved(IceCandidate[] iceCandidates) {
        peerConnection.removeIceCandidates(iceCandidates);
        Log.d(TAG, "onIceCandidatesRemoved: ");
    }

    @Override
    public void onAddStream(MediaStream mediaStream) {
        Log.d(TAG, "onAddStream: ");
    }

    @Override
    public void onRemoveStream(MediaStream mediaStream) {
        Log.d(TAG, "onRemoveStream: ");
    }

    @Override
    public void onDataChannel(DataChannel dataChannel) {
        Log.d(TAG, "onDataChannel: ");
    }

    @Override
    public void onRenegotiationNeeded() {
        Log.d(TAG, "onRenegotiationNeeded: ");
    }

    @Override
    public void onAddTrack(RtpReceiver rtpReceiver, MediaStream[] mediaStreams) {
        Log.d(TAG, "onAddTrack: ");
        MediaStreamTrack track = rtpReceiver.track();
        if (track instanceof VideoTrack) {
            VideoTrack remoteVideoTrack = (VideoTrack) track;
            remoteVideoTrack.setEnabled(true);
            if (surfaceViewRenderer != null) {
                ProxyVideoSink videoSink = new ProxyVideoSink(this.eglBase.getEglBaseContext());
                videoSink.setTarget(surfaceViewRenderer);
                remoteVideoTrack.addSink(videoSink);
            }
        }
    }

    @Override
    public void onTrack(RtpTransceiver transceiver) {
        Log.d(TAG, "onTrack: ");
        PeerConnection.Observer.super.onTrack(transceiver);
    }

    @Override
    public void onCreateSuccess(SessionDescription sdp) {
        Log.d(TAG, "onCreateSuccess: ");
        if (sdp.type == SessionDescription.Type.OFFER) {
            //设置setLocalDescription offer返回sdp
            peerConnection.setLocalDescription(this, sdp);
            if (!TextUtils.isEmpty(sdp.description)) {
                startWebRTC(sdp.description);
            }
        }
    }

    @Override
    public void onSetSuccess() {
        Log.d(TAG, "onSetSuccess: ");
    }

    @Override
    public void onCreateFailure(String s) {
        Log.d(TAG, "onCreateFailure: ");
    }

    @Override
    public void onSetFailure(String s) {
        Log.d(TAG, "onSetFailure: ");
    }
}
